﻿using System;
using System.Buffers.Text;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;

namespace HamcoWcs.Service.Common.Encryptions
{
    public class EncryptHelper
    {/// <summary>
     /// DES加密
     /// </summary>
     /// <param name="text">需要加密的文本</param>
     /// <param name="skey">密钥</param>
     /// <returns></returns>
        public static string DESEncrypt(string text, string skey)
        {
            using (DES dES = DES.Create())
            {
                byte[] bytes = Encoding.Default.GetBytes(text);
                dES.Key = Encoding.ASCII.GetBytes(MD5Encrypt(skey).Substring(0, 8));
                dES.IV = Encoding.ASCII.GetBytes(MD5Encrypt(skey).Substring(0, 8));
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, dES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(bytes, 0, bytes.Length);
                        cryptoStream.FlushFinalBlock();
                        StringBuilder stringBuilder = new StringBuilder();
                        byte[] array = memoryStream.ToArray();
                        foreach (byte b in array)
                        {
                            stringBuilder.AppendFormat("{0:X2}", b);
                        }
                        return stringBuilder.ToString();
                    }
                }
            }
        }
        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="hash">加密过的字符串</param>
        /// <param name="skey">密钥</param>
        /// <returns></returns>
        public static string DESDecrypt(string hash, string skey)
        {
            using (DES dES = DES.Create())
            {
                int num = hash.Length / 2;
                byte[] array = new byte[num];
                for (int i = 0; i < num; i++)
                {
                    int num2 = Convert.ToInt32(hash.Substring(i * 2, 2), 16);
                    array[i] = (byte)num2;
                }

                dES.Key = Encoding.ASCII.GetBytes(MD5Encrypt(skey).Substring(0, 8));
                dES.IV = Encoding.ASCII.GetBytes(MD5Encrypt(skey).Substring(0, 8));
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, dES.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(array, 0, array.Length);
                        cryptoStream.FlushFinalBlock();
                        return Encoding.Default.GetString(memoryStream.ToArray());
                    }
                }
            }
        }

        /// <summary>
        /// ASE加密
        /// </summary>
        /// <param name="text">需要加密的文本</param>
        /// <param name="skey">密钥</param>
        /// <returns></returns>
        public static string AESEncrypt(string text, string skey)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(skey);
            using (Aes aes = Aes.Create())
            {
                using (ICryptoTransform transform = aes.CreateEncryptor(bytes, aes.IV))
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        using (CryptoStream stream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write, leaveOpen: true))
                        {
                            using (StreamWriter streamWriter = new StreamWriter(stream, null, -1, leaveOpen: true))
                            {
                                streamWriter.Write(text);
                            }
                        }

                        byte[] iV = aes.IV;
                        int num = iV.Length + (int)memoryStream.Length;
                        byte[] buffer = memoryStream.GetBuffer();
                        int bytesWritten = Base64.GetMaxEncodedToUtf8Length(num);
                        byte[] array = new byte[bytesWritten];
                        Unsafe.CopyBlock(ref array[0], ref iV[0], (uint)iV.Length);
                        Unsafe.CopyBlock(ref array[iV.Length], ref buffer[0], (uint)memoryStream.Length);
                        Base64.EncodeToUtf8InPlace(array, num, out bytesWritten);
                        return Encoding.ASCII.GetString(array.AsSpan().Slice(0, bytesWritten));
                    }
                }
            }
        }

        /// <summary>
        /// ASE解密
        /// </summary>
        /// <param name="text">加密过的文本</param>
        /// <param name="skey">密钥</param>
        /// <returns></returns>
        public static string AESDecrypt(string hash, string skey)
        {
            byte[] array = Convert.FromBase64String(hash);
            byte[] array2 = new byte[16];
            byte[] array3 = new byte[array.Length - array2.Length];
            Unsafe.CopyBlock(ref array2[0], ref array[0], (uint)array2.Length);
            Unsafe.CopyBlock(ref array3[0], ref array[array2.Length], (uint)(array.Length - array2.Length));
            byte[] bytes = Encoding.UTF8.GetBytes(skey);
            using (Aes aes = Aes.Create())
            {
                using (ICryptoTransform transform = aes.CreateDecryptor(bytes, array2))
                {
                    using (MemoryStream stream = new MemoryStream(array3))
                    {
                        using (CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read))
                        {
                            using (StreamReader streamReader = new StreamReader(stream2))
                            {
                                return streamReader.ReadToEnd();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 生成 RSA 秘钥 秘钥大小必须为 2048 到 16384，并且是 8 的倍数
        /// </summary>
        /// <param name="keySize">2048-16384，%8</param>
        /// <returns></returns>
        public static (string publicKey, string privateKey) GenerateRSASecretKey(int keySize = 2048)
        {
            CheckRSAKeySize(keySize);
            using (RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider(keySize))
            {
                return (rSACryptoServiceProvider.ToXmlString(includePrivateParameters: false), rSACryptoServiceProvider.ToXmlString(includePrivateParameters: true));
            }
        }

        /// <summary>
        /// RSA加密
        /// </summary>
        /// <param name="text">需要加密的字符串</param>
        /// <param name="publicKey">公钥</param>
        /// <param name="keySize">2048-16384，%8</param>
        /// <returns></returns>
        public static string RSAEncrypt(string text, string publicKey, int keySize = 2048)
        {
            CheckRSAKeySize(keySize);
            using (RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider(keySize))
            {
                rSACryptoServiceProvider.FromXmlString(publicKey);
                return Convert.ToBase64String(rSACryptoServiceProvider.Encrypt(Encoding.Default.GetBytes(text), fOAEP: false));
            }
        }

        /// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="text">加密过的字符串</param>
        /// <param name="privateKey">私钥</param>
        /// <param name="keySize">2048-16384，%8</param>
        /// <returns></returns>
        public static string RSADecrypt(string text, string privateKey, int keySize = 2048)
        {
            CheckRSAKeySize(keySize);
            using (RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider(keySize))
            {
                rSACryptoServiceProvider.FromXmlString(privateKey);
                byte[] bytes = rSACryptoServiceProvider.Decrypt(Convert.FromBase64String(text), fOAEP: false);
                return Encoding.Default.GetString(bytes);
            }
        }

        /// <summary>
        /// 检测 RSA 长度
        /// </summary>
        /// <param name="keySize"></param>
        /// <exception cref="ArgumentException"></exception>
        private static void CheckRSAKeySize(int keySize)
        {
            if (keySize < 2048 || keySize > 16384 || keySize % 8 != 0)
            {
                throw new ArgumentException("The keySize must be between 2048 and 16384 in size and must be divisible by 8.", "keySize");
            }
        }

        /// <summary>
        ///  MD5加密，isUpcase是否输出大写
        /// </summary>
        /// <param name="str">需要加密的字符串</param>
        /// <returns>32位加密字符串</returns>
        public static string MD5Encrypt(string str)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] pwds = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
                StringBuilder pwd = new StringBuilder();
                foreach (var item in pwds)
                {
                    pwd.Append(item.ToString("X2"));
                }
                return pwd.ToString();
            }
        }

        /// <summary>
        /// MD5比较
        /// </summary>
        /// <param name="text"></param>
        /// <param name="hash"></param>
        /// <returns></returns>
        public static bool MD5Compare(string text, string hash)
        {
            string value = MD5Encrypt(text);
            return hash.Equals(value, StringComparison.OrdinalIgnoreCase);
        }

    }
}
